#include "LPC17xx.h"
#include "pwm.h"
#include "uart.h"
#include "gpio.h"
#include "pin_config.h"


/**
 * PWM1 interrupt service routine
 *
 * @param  none
 * @return none
 *
 * @brief  Set GPIO PIN's according to PWM duty
 *
 */
void pwm1_irq(void)
{
    uint32_t status;

    /* read interrupt status register */
    status = PWM1->IR;

    /* PWM base frequency reset */
    if (status & MR0_INT)
    {
        gpio_set(BANK_2,PIN_0, ON);
        gpio_set(BANK_2,PIN_1, ON);
    }
    if (status & MR1_INT)
    {
        gpio_set(BANK_2,PIN_0, OFF);
    }
    if (status & MR2_INT)
    {
        gpio_set(BANK_2,PIN_1, OFF);
    }

    /* reenable occured interrupts */
    PWM1->IR |= status;

    return;
}

/**
 * PWM1 initialization
 *
 * @param  none
 * @return none
 *
 * @brief  initialize GPIO PIN's and set initial duty cycles for all PWM pins
 *
 *
 */
void pwm_init(void)
{

	/* configure GPIO's for PWM use */
    gpio_configure(BANK_2, PIN_0, PIN_OUTPUT);
    gpio_configure(BANK_2, PIN_1, PIN_OUTPUT);
    gpio_configure(BANK_2, PIN_2, PIN_OUTPUT);
    gpio_configure(BANK_2, PIN_3, PIN_OUTPUT);
    gpio_configure(BANK_2, PIN_4, PIN_OUTPUT);
    gpio_configure(BANK_2, PIN_5, PIN_OUTPUT);

    /* reset PWM1 */
    PWM1->TCR = TCR_RESET;

    /* reset prescaler */
    PWM1->PR = 0x00;
    /* enable interrupts and reset on MR0 match */
    PWM1->MCR = PWMMR0I|PWMMR1I|PWMMR2I|PWMMR0R;

    /* set PWM1.0 with base frequency */
    PWM1->MR0 = PWM_CYCLE;

    /* set all outputs to 900us */
    PWM1->MR1 = 96000;
    PWM1->MR2 = 96000;
    PWM1->MR3 = 96000;
    PWM1->MR4 = 96000;
    PWM1->MR5 = 96000;
    PWM1->MR5 = 96000;

    /* set latch enable registers */
    PWM1->LER = LER0_EN | LER1_EN | LER2_EN | LER3_EN | LER4_EN | LER5_EN | LER6_EN;

	/* counter enable, PWM enable */
    PWM1->TCR = TCR_CNT_EN | TCR_PWM_EN;

    /* set interrupt priority */
    NVIC_SetPriority(PWM1_IRQn, PWM1_NVIC_PRIO);

    /* enable global interrupt in NVIC */
    NVIC_EnableIRQ(PWM1_IRQn);

    return;
}


/**
 * get PWM duty
 *
 * @param  uint32_t *speed
 * @return uint8_t motor (1-6)
 *
 * @brief  get PWM duty
 *
 *
 */
uint32_t pwm_get_duty(uint32_t *speed, uint8_t motor)
{
	/* switch to matching channel */
	switch(motor)
	{
		case 0x01:
			*speed = PWM1->MR1;
			break;
		case 0x02:
			*speed = PWM1->MR2;
			break;
		case 0x03:
			*speed = PWM1->MR3;
			break;
		case 0x04:
			*speed = PWM1->MR4;
			break;
		case 0x05:
			*speed = PWM1->MR5;
			break;
		case 0x06:
			*speed = PWM1->MR6;
			break;
		default:
			return 1;
	}
	return 0;
}

/**
 * set PWM1 base frequency
 *
 * @param  uint32_t value channel duty (0 - 1000)
 * @param  uint8_t channel (1-6)
 * @return none
 *
 * @brief  change base frequency of the PWM1
 *
 *
 */
uint32_t pwm_set(uint32_t value, uint8_t channel)
{

	/* switch to matching channel */
	switch(channel)
	{
		case 0x01:
			PWM1->MR1 = value;
			break;
		case 0x02:
			PWM1->MR2 = value;
			break;
		case 0x03:
			PWM1->MR3 = value;
			break;
		case 0x04:
			PWM1->MR4 = value;
			break;
		case 0x05:
			PWM1->MR5 = value;
			break;
		case 0x06:
			PWM1->MR6 = value;
			break;
		default:
			return 0x01;
	}

    /* reload latch enable registers */
    PWM1 -> LER = LER0_EN | LER1_EN | LER2_EN | LER3_EN | LER4_EN | LER5_EN | LER6_EN;

    pwm_stop();

    pwm_start();

    return 0x01;
}

/**
 * start PWM1
 *
 * @param  none
 * @return none
 *
 * @brief  start PWM1 on all channels
 *
 *
 */
void pwm_start(void)
{
	/* counter enable, PWM enable */
    PWM1 -> TCR = TCR_CNT_EN | TCR_PWM_EN;

    return;
}

/**
 * stop PWM1
 *
 * @param  none
 * @return none
 *
 * @brief  stop PWM1 on all channels
 *
 */
void pwm_stop(void)
{
	/* reset counter */
    PWM1 -> PCR = 0;

    /* Stop all PWMs */
    PWM1 -> TCR = 0x00;

    return;
}
